{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "构造新的 派生类 异常类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 162,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PersonTypeError(TypeError):\n",
    "    pass\n",
    "\n",
    "class PersonValueError(ValueError):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 定义公共人员类（基本人员类）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 163,
   "metadata": {},
   "outputs": [],
   "source": [
    "import datetime\n",
    "\n",
    "# 公共人员类（基本人员类）\n",
    "class Person:\n",
    "    _num = 0\n",
    "    def __init__(self, name, sex, birthday, ident):\n",
    "        if not (isinstance(name, str)) and sex in (\"男\", \"女\"):\n",
    "            raise PersonTypeError(name, sex)\n",
    "        try:\n",
    "            birthday = datetime.date(*birthday)\n",
    "        except:\n",
    "            raise PersonValueError(\"Wrong date:\", birthday)\n",
    "        self._name = name\n",
    "        self._sex = sex\n",
    "        self._birthday = birthday\n",
    "        self._id = ident\n",
    "        Person._num += 1\n",
    "\n",
    "    def id(self): return self._id\n",
    "    def name(self): return self._name\n",
    "    def sex(self): return self._sex\n",
    "    def birthday(self): return self._birthday\n",
    "    def age(self): return (datetime.date.today().year - self._birthday.year)\n",
    "\n",
    "    # 修改名字的函数\n",
    "    def set_name(self, name):\n",
    "        if not isinstance(name, str):\n",
    "            raise PersonValueError(\"set_name\", name)\n",
    "        self._name = name\n",
    "\n",
    "    def __lt__(self, another):\n",
    "        if not isinstance(another, Person):\n",
    "            raise PersonTypeError(another)\n",
    "        return self._id < another._id\n",
    "\n",
    "    @classmethod\n",
    "    def num(cls): return Person._num\n",
    "\n",
    "    #由于字符串join函数要求参数是可迭代对象，因此先构造元组\n",
    "    def __str__(self):\n",
    "        return \"\".join((self._id + \" \", self._name + \" \", self._sex + \" \", str(self._birthday)))\n",
    "\n",
    "    def details(self):\n",
    "        return \", \".join((\n",
    "            \"\\n\"\n",
    "            \"编号：\\t\\t\" + self._id,\n",
    "            \"\\n姓名：\\t\\t\" + self._name,\n",
    "            \"\\n性别：\\t\\t\" + self._sex,\n",
    "            \"\\n出生日期：\\t\" + str(self._birthday)\n",
    "        ))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 164,
   "metadata": {},
   "outputs": [],
   "source": [
    "p1 = Person(\"唐简单\", \"女\", (1995, 7, 15), \"1201510111\")\n",
    "p2 = Person(\"记得是\", \"男\", (1996, 2, 7), \"1201510561\")\n",
    "p3 = Person(\"开会\", \"男\", (1985, 9, 25), \"1202350111\")\n",
    "p4 = Person(\"换衣服\", \"女\", (1991, 1, 11), \"1201510199\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 165,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1201510111 唐简单 女 1995-07-15\n",
      "1201510561 记得是 男 1996-02-07\n",
      "1202350111 开会 男 1985-09-25\n",
      "1201510199 换衣服 女 1991-01-11\n"
     ]
    }
   ],
   "source": [
    "plist2 = [p1, p2, p3, p4]\n",
    "for p in plist2:\n",
    "    print(p)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 166,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "After sorting:\n",
      "\n",
      "编号：\t\t1201510111, \n",
      "姓名：\t\t唐简单, \n",
      "性别：\t\t女, \n",
      "出生日期：\t1995-07-15\n",
      "\n",
      "编号：\t\t1201510199, \n",
      "姓名：\t\t换衣服, \n",
      "性别：\t\t女, \n",
      "出生日期：\t1991-01-11\n",
      "\n",
      "编号：\t\t1201510561, \n",
      "姓名：\t\t记得是, \n",
      "性别：\t\t男, \n",
      "出生日期：\t1996-02-07\n",
      "\n",
      "编号：\t\t1202350111, \n",
      "姓名：\t\t开会, \n",
      "性别：\t\t男, \n",
      "出生日期：\t1985-09-25\n"
     ]
    }
   ],
   "source": [
    "print(\"\\nAfter sorting:\")\n",
    "plist2.sort()\n",
    "for p in plist2:\n",
    "    print(p.details())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 167,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "people created: 4 \n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(\"people created:\", Person.num(), \"\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 定义 学生类（由公共类派生）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 168,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "class Student(Person):\n",
    "    _id_num = 0\n",
    "\n",
    "    @classmethod\n",
    "    def _id_gen(cls):  #实现学号生成规则\n",
    "        cls._id_num += 1\n",
    "        year = datetime.date.today().year\n",
    "        return \"1{:04}{:05}\".format(year, cls._id_num)\n",
    "\n",
    "    def __init__(self, name, sex, birthday, department):\n",
    "        Person.__init__(self, name, sex, birthday, Student._id_gen())\n",
    "        self._department = department\n",
    "        self._enroll_date = datetime.date.today()\n",
    "        self._courses = {} #一个空字典\n",
    "\n",
    "    def set_course(self, course_name):\n",
    "        self._courses[course_name] = None\n",
    "\n",
    "    def set_score(self, course_name, score):\n",
    "        if course_name not in self._courses:\n",
    "            raise PersonValueError(\"No this course selected:\", course_name)\n",
    "        self._courses[course_name] = score\n",
    "\n",
    "    def scores(self):\n",
    "        return [(cname, self._courses[cname]) for cname in self._courses]\n",
    "\n",
    "    def details(self):\n",
    "        #更推荐的是使用super()方式调用基类中的属性和方法\n",
    "        return \", \".join((Person.details(self),\n",
    "                          \"\\n入学时间：\\t\" + str(self._enroll_date),\n",
    "                          \"\\n院系：\\t\\t\" + str(self._department),\n",
    "                          \"\\n课程记录：\\t\" + str(self.scores())\n",
    "                          ))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 169,
   "metadata": {},
   "outputs": [],
   "source": [
    "p5 = Student(\"张子玉\", \"女\", (1994, 10, 16), department=\"制造\")\n",
    "p6 = Student(\"李国林\", \"男\", (1992,5, 12), department=\"经管\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 170,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1201900001 张子玉 女 1994-10-16\n"
     ]
    }
   ],
   "source": [
    "print(p5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 171,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "编号：\t\t1201900001, \n",
      "姓名：\t\t张子玉, \n",
      "性别：\t\t女, \n",
      "出生日期：\t1994-10-16, \n",
      "入学时间：\t2019-12-16, \n",
      "院系：\t\t制造, \n",
      "课程记录：\t[]\n"
     ]
    }
   ],
   "source": [
    "print(p5.details())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 172,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "编号：\t\t1201900001, \n",
      "姓名：\t\t张子玉, \n",
      "性别：\t\t女, \n",
      "出生日期：\t1994-10-16, \n",
      "入学时间：\t2019-12-16, \n",
      "院系：\t\t制造, \n",
      "课程记录：\t[('数学', None)]\n"
     ]
    }
   ],
   "source": [
    "p5.set_course(\"数学\")\n",
    "print(p5.details())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 173,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "编号：\t\t1201900001, \n",
      "姓名：\t\t张子玉, \n",
      "性别：\t\t女, \n",
      "出生日期：\t1994-10-16, \n",
      "入学时间：\t2019-12-16, \n",
      "院系：\t\t制造, \n",
      "课程记录：\t[('数学', 118)]\n"
     ]
    }
   ],
   "source": [
    "p5.set_score(\"数学\", 118)\n",
    "print(p5.details())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 教工类的实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 174,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "# 教工类的实现\n",
    "class Staff(Person):\n",
    "    _id_num = 0\n",
    "\n",
    "    @classmethod\n",
    "    def _id_gen(cls, birthday):  #实现职工号生成规则\n",
    "        cls._id_num += 1\n",
    "        birth_year = datetime.date(*birthday).year\n",
    "        return \"0{:04}{:05}\".format(birth_year, cls._id_num)\n",
    "\n",
    "    def __init__(self, name, sex, birthday, entry_date=None):\n",
    "        super().__init__(name, sex, birthday, Staff._id_gen(birthday))\n",
    "\n",
    "        if entry_date:\n",
    "            try:\n",
    "                self._entry_date = datetime.date(*entry_date)\n",
    "            except:\n",
    "                raise PersonValueError(\"Wrong date：\", entry_date)\n",
    "        else:\n",
    "            self._entry_date = datetime.date.today()\n",
    "\n",
    "        self._salary = 2000 #设置默认最低工资\n",
    "        self._department = \"未定\"\n",
    "        self._positon = \"未定\"\n",
    "\n",
    "    def set_salary(self, amount):\n",
    "        if not type(amount) is int:\n",
    "            raise TypeError\n",
    "        self._salary = amount\n",
    "\n",
    "    def set_position(self, position):\n",
    "        self._positon = position\n",
    "    def set_department(self, department):\n",
    "        self._department = department\n",
    "\n",
    "    def details(self):\n",
    "        return \", \".join((\n",
    "            super().details(),\n",
    "            \"\\n入职日期：\\t\" + str(self._entry_date),\n",
    "            \"\\n院系：\\t\\t\" + str(self._department),\n",
    "            \"\\n职位：\\t\\t\" + str(self._positon),\n",
    "            \"\\n工资：\\t\\t\" + str(self._salary)\n",
    "        ))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 175,
   "metadata": {},
   "outputs": [],
   "source": [
    "p7 = Staff(\"浮动板\", \"女\", (1974, 10, 16))\n",
    "p8 = Staff(\"人多少\", \"男\", (1942,5, 12))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 176,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0197400001 浮动板 女 1974-10-16\n",
      "0194200002 人多少 男 1942-05-12\n"
     ]
    }
   ],
   "source": [
    "print(p7)\n",
    "print(p8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 177,
   "metadata": {},
   "outputs": [],
   "source": [
    "p7.set_department(\"数学\")\n",
    "p7.set_position(\"副教授\")\n",
    "p7.set_salary(12000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 178,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "编号：\t\t0197400001, \n",
      "姓名：\t\t浮动板, \n",
      "性别：\t\t女, \n",
      "出生日期：\t1974-10-16, \n",
      "入职日期：\t2019-12-16, \n",
      "院系：\t\t数学, \n",
      "职位：\t\t副教授, \n",
      "工资：\t\t12000\n",
      "\n",
      "编号：\t\t0194200002, \n",
      "姓名：\t\t人多少, \n",
      "性别：\t\t男, \n",
      "出生日期：\t1942-05-12, \n",
      "入职日期：\t2019-12-16, \n",
      "院系：\t\t未定, \n",
      "职位：\t\t未定, \n",
      "工资：\t\t2000\n"
     ]
    }
   ],
   "source": [
    "print(p7.details())\n",
    "print(p8.details())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
